package com.jctrip.hotel.source.service.greentree.impl;

import com.baomidou.mybatisplus.core.toolkit.AES;
import com.jctrip.hotel.common.enums.OrderStatusEnum;
import com.jctrip.hotel.common.enums.SourceEnum;
import com.jctrip.hotel.common.util.*;
import com.jctrip.hotel.source.client.GreenTreeHotelClient;
import com.jctrip.hotel.source.client.GreenTreeOrderClient;
import com.jctrip.hotel.source.client.GreenTreeOtherHotelClient;
import com.jctrip.hotel.source.model.OrderDataResult;
import com.jctrip.hotel.source.model.PriceCheckParam;
import com.jctrip.hotel.source.model.greentree.req.*;
import com.jctrip.hotel.source.model.greentree.resp.*;
import com.jctrip.hotel.source.model.wehotel.req.OrderData;
import com.jctrip.hotel.source.service.HotelCommonTaskService;
import com.jctrip.hotel.source.service.greentree.GreenTreeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @Author：Haruhi
 * @description:
 * @Date：2023/8/30 22:17
 * @Package：com.jctrip.hotel.source.service.greentree.impl
 * @Project：hotel-main
 */
@Service
@Slf4j
public class GreenTreeServiceImpl implements GreenTreeService {

    @Resource
    private GreenTreeHotelClient greenTreeClient;
    @Resource
    private GreenTreeOrderClient greenTreeOrderClient;
    @Resource
    private GreenTreeOtherHotelClient greenTreeOtherHotelClient;
    @Autowired
    private HotelCommonTaskService hotelCommonTaskService;

    @Override
    public String parseHotelId(String innId) {
        if (StringUtils.isBlank(innId)) {
            return null;
        }

        return innId.substring(SourceEnum.GREENTREE.getCode().length());
    }

    @Override
    public String parseInnId(String hotelId) {
        if (StringUtils.isBlank(hotelId)) {
            return null;
        }

        return SourceEnum.GREENTREE.getCode() + hotelId;
    }

    @Override
    public GetAllHotelInfoResp getAllHotelInfo(GetAllHotelInfoReq getAllHotelInfoReq) {
        String errorStr = "";
        try {
            String xmlData = greenTreeClient.getAllHotelInfo(buildParam(XMLUtil.convertObjectToXml(getAllHotelInfoReq)));
            errorStr = getRespError(xmlData) + "\n" + xmlData;
            GetAllHotelInfoResp getAllHotelInfoResp = XMLUtil.convertXmlToObject(xmlData, GetAllHotelInfoResp.class);
            if (null == getAllHotelInfoResp) {
                log.error("getAllHotelInfo error respData {}", xmlData);
                throw new RuntimeException("获取所有酒店信息为空");
            }
            if (!"SUCCESS".equals(getAllHotelInfoResp.getResult())) {
                log.error("getHotelInfo error respData {}", xmlData);
                throw new RuntimeException("获取所有酒店信息失败");
            }
            return getAllHotelInfoResp;

        } catch (Exception e) {
            throw new RuntimeException(errorStr + "\n" + e.getMessage());
        }
    }

    //todo 获取酒店信息。返回的xml格式需要额外处理,阴间<`\UFEFF`定义为零宽无换行的空格>
    @Override
    public GetHotelInfoResp getHotelInfo(GetHotelInfoReq getHotelInfoReq) {
        String errorStr = "";
        try {
//            log.info("请求xml:" + XMLUtil.convertObjectToXml(getHotelInfoReq));
            String xmlData = greenTreeClient.getHotelInfo(buildParam(XMLUtil.convertObjectToXml(getHotelInfoReq)));
            xmlData = xmlData.replaceAll("\n", "").replaceAll("\uFEFF", "");
            errorStr = getRespError(xmlData) + "\n" + xmlData;
//            log.info("返回xml:" + xmlData);
            GetHotelInfoResp getHotelInfoResp = XMLUtil.convertXmlToObject(xmlData, GetHotelInfoResp.class);
//            log.info("返回对象:"+JsonUtil.toString(getHotelInfoResp));
            if (null == getHotelInfoResp) {
                log.error("getHotelInfo error respData {}", xmlData);
                throw new RuntimeException("获取酒店信息为空");
            }
            if (!"SUCCESS".equals(getHotelInfoResp.getResult())) {
                log.error("getHotelInfo error respData {}", xmlData);
                throw new RuntimeException("查询失败");
            }
            return getHotelInfoResp;

        } catch (Exception e) {
            throw new RuntimeException(errorStr + "\n" + e.getMessage());
        }
    }

    @Override
    public GetHotelInfoByCodeResp getHotelInfoByCode(String hotelId) {
        long timeStamp = new Date().getTime() / 1000;
        String content = "jiachengshanglv" + "C" + timeStamp;
        String key = "R6xcku5XeW1V6KhR";
        String iv = "jiachengshanglv=";
        String sign = SignUtil.encryptWithVi(content, key, iv);
        GetHotelInfoByCodeReq getHotelInfoByCodeReq = GetHotelInfoByCodeReq.builder()
                .hotelCode(hotelId)
                .chainCode("jiachengshanglv")
                .language("C")
                .sign(sign)
                .timeStamp(timeStamp)
                .build();
        GetHotelInfoByCodeResp hotelInfoData = greenTreeClient.getHotelInfoByCode(getHotelInfoByCodeReq);

        return hotelInfoData;
    }

    @Override
    public GetRoomTypeListResp getRoomTypeList(GetRoomTypeListReq getRoomTypeListReq) {
        if (StringUtils.isBlank(getRoomTypeListReq.getReqHotels().getReqHotel().getHotelCode())) {
            throw new RuntimeException("酒店编号为空");
        }
        String errorStr = "";
        try {
//            log.info("请求xml:" + XMLUtil.convertObjectToXml(getRoomTypeListReq));
            String xmlData = greenTreeClient.getRoomTypeList(buildParam(XMLUtil.convertObjectToXml(getRoomTypeListReq)));
            errorStr = getRespError(xmlData) + "\n" + xmlData;
//            log.info("返回xml:" + xmlData);
            GetRoomTypeListResp getRoomTypeListResp = XMLUtil.convertXmlToObject(xmlData, GetRoomTypeListResp.class);
//            log.info("返回对象:"+JsonUtil.toString(getRoomTypeListResp));
            if (null == getRoomTypeListResp) {
                log.error("getRoomTypeList error respData {}", xmlData);
                throw new RuntimeException("获取房态信息为空");
            }
            if (!"SUCCESS".equals(getRoomTypeListResp.getResult())) {
                log.error("getRoomTypeList error respData {}", xmlData);
                throw new RuntimeException("查询失败");
            }
            return getRoomTypeListResp;
        } catch (Exception e) {
            throw new RuntimeException(errorStr + "\n" + e.getMessage());
        }
    }


    @Override
    public GetAllRoomCountAndPriceResp getAllRoomCountAndPrice(GetAllRoomCountAndPriceReq getAllRoomCountAndPriceReq) {
        if (StringUtils.isBlank(getAllRoomCountAndPriceReq.getHotelCode())) {
            throw new RuntimeException("酒店编号为空");
        }
        if (StringUtils.isBlank(getAllRoomCountAndPriceReq.getStartDate()) || StringUtils.isBlank(getAllRoomCountAndPriceReq.getEndDate())) {
            throw new RuntimeException("开始或结束日期为空");
        }
        String errorStr = "";
        try {
//            log.info("请求xml:" + XMLUtil.convertObjectToXml(getAllRoomCountAndPriceReq));
            String xmlData = greenTreeClient.getAllRoomCountAndPrice(buildParam(XMLUtil.convertObjectToXml(getAllRoomCountAndPriceReq)));
            errorStr = getRespError(xmlData) + "\n" + xmlData;
//            log.info("返回xml:" + xmlData);
            GetAllRoomCountAndPriceResp getAllRoomCountAndPriceResp = XMLUtil.convertXmlToObject(xmlData, GetAllRoomCountAndPriceResp.class);
//            log.info("返回对象:"+JsonUtil.toString(getAllRoomCountAndPriceResp));
            if (null == getAllRoomCountAndPriceResp) {
                log.error("getAllRoomCountAndPrice error respData {}", xmlData);
                throw new RuntimeException("获取房态信息为空");
            }
            if (!"SUCCESS".equals(getAllRoomCountAndPriceResp.getResult())) {
                log.error("getAllRoomCountAndPrice error respData {}", xmlData);
                throw new RuntimeException("查询失败");
            }
            return getAllRoomCountAndPriceResp;
        } catch (Exception e) {
            throw new RuntimeException(errorStr + "\n" + e.getMessage());
        }
    }

    @Override
    public BookingCheckResp bookingCheck(BookingCheckReq bookingCheckReq) {
        if (StringUtils.isBlank(bookingCheckReq.getHotelCode())) {
            throw new RuntimeException("酒店编号为空");
        }
        if (StringUtils.isBlank(bookingCheckReq.getStartDate()) || StringUtils.isBlank(bookingCheckReq.getEndDate())) {
            throw new RuntimeException("开始或结束日期为空");
        }
        String errorStr = "";
        try {
//            log.info("请求对象:" + JsonUtil.toString(bookingCheckReq));
//            log.info("请求xml:" + XMLUtil.convertObjectToXml(bookingCheckReq));
            String xmlData = greenTreeOrderClient.bookingCheck(buildParam(XMLUtil.convertObjectToXml(bookingCheckReq)));
            errorStr = getRespError(xmlData) + "\n" + xmlData;
//            log.info("返回xml:" + xmlData);
            BookingCheckResp bookingCheckResp = XMLUtil.convertXmlToObject(xmlData, BookingCheckResp.class);
//            log.info("返回对象:"+JsonUtil.toString(bookingCheckResp));
            if (null == bookingCheckResp) {
                log.error("bookingCheck error respData {}", xmlData);
                throw new RuntimeException("下单检查信息为空");
            }
            if (!"SUCCESS".equals(bookingCheckResp.getResult())) {
                log.error("bookingCheck error respData {}", xmlData);
                throw new RuntimeException("下单检查失败");
            }
            return bookingCheckResp;
        } catch (Exception e) {
            throw new RuntimeException(errorStr + "\n" + e.getMessage());
        }
    }

    @Override
    public SearchBookingResp searchBooking(SearchBookingReq searchBookingReq) {
        if (StringUtils.isBlank(searchBookingReq.getHotelCode())) {
            throw new RuntimeException("酒店编号为空");
        }
        if (StringUtils.isBlank(searchBookingReq.getUniqueID()) && StringUtils.isBlank(searchBookingReq.getAgentUniqueID())) {
            throw new RuntimeException("订单编号为空");
        }
        String errorStr = "";
        try {
//            log.info("请求对象:" + JsonUtil.toString(searchBookingReq));
//            log.info("请求xml:" + XMLUtil.convertObjectToXml(searchBookingReq));
            String xmlData = greenTreeOrderClient.searchBooking(buildParam(XMLUtil.convertObjectToXml(searchBookingReq)));
            errorStr = getRespError(xmlData) + "\n" + xmlData;
//            log.info("返回xml:" + xmlData);
            SearchBookingResp searchBookingResp = XMLUtil.convertXmlToObject(xmlData, SearchBookingResp.class);
//            log.info("返回对象:"+JsonUtil.toString(searchBookingResp));
            if (null == searchBookingResp) {
                log.error("searchBooking error respData {}", xmlData);
                throw new RuntimeException("查询信息为空");
            }
            if (!"SUCCESS".equals(searchBookingResp.getResult())) {
                log.error("searchBooking error respData {}", xmlData);
                throw new RuntimeException("查询失败");
            }
            return searchBookingResp;
        } catch (Exception e) {
            throw new RuntimeException(errorStr + "\n" + e.getMessage());
        }
    }

    @Override
    public OrderData queryOrderData(SearchBookingReq searchBookingReq) {
        SearchBookingResp searchBookingResp = searchBooking(searchBookingReq);
        OrderData result = new OrderData();
        result.setOrderCode(searchBookingResp.getResvInfos().getResvInfoList().get(0).getUniqueID());
        result.setExternalId(searchBookingResp.getAgentUniqueID());
        Integer roomStatu = 0;
        switch (searchBookingResp.getResvInfos().getResvInfoList().get(0).getStatus()) {
            case "R": //预定
                roomStatu = 1;
                break;
            case "C": //取消
                roomStatu = 2;
                break;
            case "O": //已离店
                roomStatu = 5;
                break;
            case "I": //入住
                roomStatu = 4;
                break;
            case "QO": //欠款离店
                roomStatu = 5;
                break;
            case "NW": //noshow
                roomStatu = 3;
                break;
        }
        result.setOrderState(roomStatu);
        return result;
    }

    @Override
    public OrderDataResult postOrder(CreateBookingReq createOrderReq, PriceCheckParam priceCheck) {
        /**
         * 单间多天，预定的话，会导致中介方查询预订时，分不清订单状态；
         * 每个订单请求只支持一间房，如果中介方下多间房的订单，建议订单拆分请求
         */
        String errorStr = "";
        try {
            // 下单前校验
            BookingCheckReq bookingCheckReq = getBookingCheckReqInfo(createOrderReq);
            BookingCheckResp bookingCheckResp = bookingCheck(bookingCheckReq);

            // 容差判断
            BigDecimal raisedTotalPrice = BigDecimal.valueOf(0);
            // 房间多天总价格
            BigDecimal greentreeTotalRate = BigDecimal.ZERO;
            List<BookingCheckResp.ReqRooms.ReqDate.ReqRoom.RoomRate> reqRoomRates = bookingCheckResp.getReqRooms().getReqDate()
                    .stream().map(e -> e.getReqRoom().getRoomRate()).collect(Collectors.toList());
            for (BookingCheckResp.ReqRooms.ReqDate.ReqRoom.RoomRate roomRate : reqRoomRates) {
                raisedTotalPrice = raisedTotalPrice.add(
                        priceCheck.getRaiseFunc().apply(BigDecimal.valueOf(roomRate.getPrice())));
                greentreeTotalRate = greentreeTotalRate.add(BigDecimal.valueOf(roomRate.getPrice()));
            }
            Integer roomCount = createOrderReq.getReservationInfo().getReqRooms().getReqRoom().getRoomCount();
            // todo 目前原价判断，无容差
            if (priceCheck.getTotalRate().compareTo(greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount))
                    .subtract(priceCheck.getTolerancePrice())) < 0) {
                String error = String.format("订单销售价不能低于采购总价，订单销售价=%s，采购总价=%s, 容差金额=%s, 目前差额=%s",
                        priceCheck.getTotalRate(),
                        greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount)),
                        priceCheck.getTolerancePrice(),
                        greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount)).subtract(priceCheck.getTotalRate()));
                hotelCommonTaskService.insertOrderErrorLog(createOrderReq.getReservationInfo().getAgentUniqueID(),
                        JsonUtil.toString(createOrderReq), error);
                log.error("订单销售价不能低于采购总价，订单销售价={}，采购总价={}, 容差金额={}, 目前差额={}",
                        priceCheck.getTotalRate(), greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount))
                        , priceCheck.getTolerancePrice(),
                        greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount)).subtract(priceCheck.getTotalRate()));
                throw new RuntimeException("订单销售价不能低于采购总价");
            }

            // 订单总金额
            String commitPrice = getCommitPrice(createOrderReq.getReservationInfo().getComment());
            if (greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount))
                    .compareTo(new BigDecimal(commitPrice)) != 0) {
                throw new RuntimeException("与实时价格不合，请确认后重新下单");
            }

            // 下单
//            log.info("请求对象:" + JsonUtil.toString(createOrderReq));
//            log.info("请求xml:" + XMLUtil.convertObjectToXml(createOrderReq));
            String xmlData = greenTreeOrderClient.createBooking(buildParam(XMLUtil.convertObjectToXml(createOrderReq)));
            errorStr = getRespError(xmlData) + "\n" + xmlData;
//            log.info("返回xml:" + xmlData);
            CreateBookingResp createBookingResp = XMLUtil.convertXmlToObject(xmlData, CreateBookingResp.class);
//            log.info("返回对象:"+JsonUtil.toString(createBookingResp));
            if (null == createBookingResp) {
                log.error("createBooking error respData {}", xmlData);
                throw new RuntimeException("下单信息为空");
            }
            if (!"SUCCESS".equals(createBookingResp.getResult())) {
                log.error("createBooking error respData {}", xmlData);
                throw new RuntimeException("下单失败");
            }
            return OrderDataResult.builder()
                    .orderCode(createBookingResp.getUniqueID()) //订单编号
                    .externalId(createOrderReq.getReservationInfo().getAgentUniqueID()) //中介订单号
                    .orderState(OrderStatusEnum.BOOK_SUCCESS.getCode())
                    .totalRate(greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount)))
                    .requestJsonStr(JsonUtil.toString(createOrderReq))
                    .responseJsonStr(JsonUtil.toString(createBookingResp))
                    .build();
        } catch (Exception e) {
            throw new RuntimeException(errorStr + "\n" + e.getMessage());
        }
    }

    @Override
    public CreateBookingResp createBooking(CreateBookingReq createBookingReq) {
        String errorStr = "";
        try {
            // 下单前校验
            BookingCheckReq bookingCheckReq = getBookingCheckReqInfo(createBookingReq);
            BookingCheckResp bookingCheckResp = bookingCheck(bookingCheckReq);

            // 下单
//            log.info("请求对象:" + JsonUtil.toString(createBookingReq));
//            log.info("请求xml:" + XMLUtil.convertObjectToXml(createBookingReq));
            String xmlData = greenTreeOrderClient.createBooking(buildParam(XMLUtil.convertObjectToXml(createBookingReq)));
            errorStr = getRespError(xmlData) + "\n" + xmlData;
//            log.info("返回xml:" + xmlData);
            CreateBookingResp createBookingResp = XMLUtil.convertXmlToObject(xmlData, CreateBookingResp.class);
//            log.info("返回对象:"+JsonUtil.toString(createBookingResp));
            if (null == createBookingResp) {
                log.error("createBooking error respData {}", xmlData);
                throw new RuntimeException("下单信息为空");
            }
            if (!"SUCCESS".equals(createBookingResp.getResult())) {
                log.error("createBooking error respData {}", xmlData);
                throw new RuntimeException("下单失败");
            }
            return createBookingResp;
        } catch (Exception e) {
            throw new RuntimeException(errorStr + "\n" + e.getMessage());
        }
    }

    /**
     * 拷贝下单对象值到校验对象
     */
    private BookingCheckReq getBookingCheckReqInfo(CreateBookingReq createBookingReq) {
        BookingCheckReq bookingCheckReq = BookingCheckReq.builder()
                .startDate(createBookingReq.getReservationInfo().getStartDate())
                .endDate(createBookingReq.getReservationInfo().getEndDate())
                .hotelCode(createBookingReq.getReservationInfo().getHotelCode())
                .reqRooms(BookingCheckReq.ReqRooms.builder()
                        .reqRoom(BookingCheckReq.ReqRooms.ReqRoom.builder()
                                .roomTypeCode(createBookingReq.getReservationInfo().getReqRooms().getReqRoom().getRoomTypeCode())
                                .roomCount(createBookingReq.getReservationInfo().getReqRooms().getReqRoom().getRoomCount())
                                .build())
                        .build())
                .build();
        bookingCheckReq.setChainCode(createBookingReq.getChainCode());

        return bookingCheckReq;
    }

    @Override
    public CancelBookingResp cancelBooking(CancelBookingReq cancelBookingReq) {
        if (StringUtils.isBlank(cancelBookingReq.getUniqueID())) {
            throw new RuntimeException("订单号为空");
        }
        String errorStr = "";
        try {
//            log.info("请求对象:" + JsonUtil.toString(cancelBookingReq));
//            log.info("请求xml:" + XMLUtil.convertObjectToXml(cancelBookingReq));
            String xmlData = greenTreeOrderClient.cancelBooking(buildParam(XMLUtil.convertObjectToXml(cancelBookingReq)));
            errorStr = getRespError(xmlData) + "\n" + xmlData;
//            log.info("返回xml:" + xmlData);
            CancelBookingResp cancelBookingResp = XMLUtil.convertXmlToObject(xmlData, CancelBookingResp.class);
//            log.info("返回对象:"+JsonUtil.toString(cancelBookingResp));
            if (null == cancelBookingResp) {
                log.error("cancelBookingResp error respData {}", xmlData);
                throw new RuntimeException("取消订单信息为空");
            }
            if (!"SUCCESS".equals(cancelBookingResp.getResult())) {
                log.error("cancelBookingResp error respData {}", xmlData);
                throw new RuntimeException("取消订单失败");
            }
            return cancelBookingResp;
        } catch (Exception e) {
            throw new RuntimeException(errorStr + "\n" + e.getMessage());
        }
    }

    @Override
    public GetBreakfastInfoResp getBreakfastInfo(GetBreakfastInfoReq getBreakfastInfoReq) {
        if (StringUtils.isBlank(getBreakfastInfoReq.getHotelCode())) {
            throw new RuntimeException("酒店id为空");
        }
        String errorStr = "";
        try {
//            log.info("请求对象:" + JsonUtil.toString(getBreakfastInfoReq));
//            log.info("请求xml:" + XMLUtil.convertObjectToXml(getBreakfastInfoReq));
            String xmlData = greenTreeOtherHotelClient.getBreakfastInfo(buildParam(XMLUtil.convertObjectToXml(getBreakfastInfoReq)));
            errorStr = getRespError(xmlData) + "\n" + xmlData;
//            log.info("返回xml:" + xmlData);
            GetBreakfastInfoResp getBreakfastInfoResp = XMLUtil.convertXmlToObject(xmlData, GetBreakfastInfoResp.class);
//            log.info("返回对象:"+JsonUtil.toString(getBreakfastInfoResp));
            if (null == getBreakfastInfoResp) {
                log.error("getBreakfastInfoResp error respData {}", xmlData);
                throw new RuntimeException("获取早餐信息为空");
            }
            if (!"SUCCESS".equals(getBreakfastInfoResp.getResult())) {
                log.error("getBreakfastInfoResp error respData {}", xmlData);
                throw new RuntimeException("获取早餐信息失败");
            }
            return getBreakfastInfoResp;
        } catch (Exception e) {
            throw new RuntimeException(errorStr + "\n" + e.getMessage());
        }
    }

    @Override
    public GetActivityRoomListResp getActivityRoomList(GetActivityRoomListReq getActivityRoomListReq) {
        if (StringUtils.isBlank(getActivityRoomListReq.getReqHotels().getReqHotel().getHotelCode())) {
            throw new RuntimeException("酒店id为空");
        }
        String errorStr = "";
        try {
//            log.info("请求对象:" + JsonUtil.toString(getActivityRoomListReq));
//            log.info("请求xml:" + XMLUtil.convertObjectToXml(getActivityRoomListReq));
            String xmlData = greenTreeOtherHotelClient.getActivityRoomList(buildParam(XMLUtil.convertObjectToXml(getActivityRoomListReq)));
            errorStr = getRespError(xmlData) + "\n" + xmlData;
//            log.info("返回xml:" + xmlData);
            GetActivityRoomListResp getActivityRoomListResp = XMLUtil.convertXmlToObject(xmlData, GetActivityRoomListResp.class);
//            log.info("返回对象:"+JsonUtil.toString(getActivityRoomListResp));
            if (null == getActivityRoomListResp) {
                log.error("getActivityRoomListResp error respData {}", xmlData);
                throw new RuntimeException("获取活动房型列表信息为空");
            }
            if (!"SUCCESS".equals(getActivityRoomListResp.getResult())) {
                log.error("getActivityRoomListResp error respData {}", xmlData);
                throw new RuntimeException("获取活动房型列表信息失败");
            }
            return getActivityRoomListResp;
        } catch (Exception e) {
            throw new RuntimeException(errorStr + "\n" + e.getMessage());
        }

    }

    @Override
    public GetAllRoomCountAndPriceActivityResp getAllRoomCountAndPriceActivity(GetAllRoomCountAndPriceActivityReq getAllRoomCountAndPriceActivityReq) {
        if (StringUtils.isEmpty(getAllRoomCountAndPriceActivityReq.getHotelCode())) {
            throw new RuntimeException("酒店id为空");
        }
        String errorStr = "";
        try {
//            log.info("请求对象:" + JsonUtil.toString(getAllRoomCountAndPriceActivityReq));
//            log.info("请求xml:" + XMLUtil.convertObjectToXml(getAllRoomCountAndPriceActivityReq));
            String xmlData = greenTreeOtherHotelClient.getAllRoomCountAndPriceActivity(buildParam(XMLUtil.convertObjectToXml(getAllRoomCountAndPriceActivityReq)));
            errorStr = getRespError(xmlData) + "\n" + xmlData;
//            log.info("返回xml:" + xmlData);
            GetAllRoomCountAndPriceActivityResp getAllRoomCountAndPriceActivityResp = XMLUtil.convertXmlToObject(xmlData, GetAllRoomCountAndPriceActivityResp.class);
//            log.info("返回对象:"+JsonUtil.toString(getAllRoomCountAndPriceActivityResp));
            if (null == getAllRoomCountAndPriceActivityResp) {
                log.error("getAllRoomCountAndPriceActivityResp error respData {}", xmlData);
                throw new RuntimeException("获取活动房态为空");
            }
            if (!"SUCCESS".equals(getAllRoomCountAndPriceActivityResp.getResult())) {
                log.error("getAllRoomCountAndPriceActivityResp error respData {}", xmlData);
                throw new RuntimeException("获取活动房态失败");
            }
            return getAllRoomCountAndPriceActivityResp;
        } catch (Exception e) {
            throw new RuntimeException(errorStr + " :" + getAllRoomCountAndPriceActivityReq.getHotelCode() + "-" +
                    getAllRoomCountAndPriceActivityReq.getReqRooms().getReqRoom().getRoomTypeCode() + "-" +
                    getAllRoomCountAndPriceActivityReq.getReqRooms().getReqRoom().getActivityCode() +
                    "\n" + e.getMessage());
        }
    }

    @Override
    public BookingCheckActivityResp bookingCheckActivity(BookingCheckActivityReq bookingCheckActivityReq) {
        if (StringUtils.isEmpty(bookingCheckActivityReq.getHotelCode())) {
            throw new RuntimeException("酒店id为空");
        }
        String errorStr = "";
        try {
//            log.info("请求对象:" + JsonUtil.toString(bookingCheckActivityReq));
//            log.info("请求xml:" + XMLUtil.convertObjectToXml(bookingCheckActivityReq));
            String xmlData = greenTreeOrderClient.bookingCheckActivity(buildParam(XMLUtil.convertObjectToXml(bookingCheckActivityReq)));
            errorStr = getRespError(xmlData) + "\n" + xmlData;
//            log.info("返回xml:" + xmlData);
            BookingCheckActivityResp bookingCheckActivityResp = XMLUtil.convertXmlToObject(xmlData, BookingCheckActivityResp.class);
//            log.info("返回对象:"+JsonUtil.toString(bookingCheckActivityResp));
            if (null == bookingCheckActivityResp) {
                log.error("bookingCheckActivityResp error respData {}", xmlData);
                throw new RuntimeException("获取可用房态信息为空");
            }
            if (!"SUCCESS".equals(bookingCheckActivityResp.getResult())) {
                log.error("bookingCheckActivityResp error respData {}", xmlData);
                throw new RuntimeException("获取可用房态信息失败");
            }
            return bookingCheckActivityResp;
        } catch (Exception e) {
            throw new RuntimeException(errorStr + "\n" + e.getMessage());
        }

    }

    @Override
    public CreateBookingActivityResp createBookingActivity(CreateBookingActivityReq createBookingActivityReq) {
        String errorStr = "";
        try {
//            log.info("请求对象:" + JsonUtil.toString(createBookingActivityReq));
//            log.info("请求xml:" + XMLUtil.convertObjectToXml(createBookingActivityReq));
            String xmlData = greenTreeOrderClient.createBookingActivity(buildParam(XMLUtil.convertObjectToXml(createBookingActivityReq)));
            errorStr = getRespError(xmlData) + "\n" + xmlData;
//            log.info("返回xml:" + xmlData);
            CreateBookingActivityResp createBookingActivityResp = XMLUtil.convertXmlToObject(xmlData, CreateBookingActivityResp.class);
//            log.info("返回对象:"+JsonUtil.toString(createBookingActivityResp));
            if (null == createBookingActivityResp) {
                log.error("createBookingActivityResp error respData {}", xmlData);
                throw new RuntimeException("活动下单信息为空");
            }
            if (!"SUCCESS".equals(createBookingActivityResp.getResult())) {
                log.error("createBookingActivityResp error respData {}", xmlData);
                throw new RuntimeException("活动下单失败");
            }
            return createBookingActivityResp;
        } catch (Exception e) {
            throw new RuntimeException(errorStr + "\n" + e.getMessage());
        }

    }

    @Override
    public GetAgreementPriceResp getAgreementPrice(GetAgreementPriceReq getAgreementPriceReq) {
        if (StringUtils.isBlank(getAgreementPriceReq.getHotelCode())) {
            throw new RuntimeException("酒店编号为空");
        }
        if (StringUtils.isBlank(getAgreementPriceReq.getStartDate()) || StringUtils.isBlank(getAgreementPriceReq.getEndDate())) {
            throw new RuntimeException("开始或结束日期为空");
        }
        String errorStr = "";
        try {
//            log.info("请求xml:" + XMLUtil.convertObjectToXml(getAgreementPriceReq));
            String xmlData = greenTreeClient.getAgreementPrice(buildParam(XMLUtil.convertObjectToXml(getAgreementPriceReq)));
            errorStr = getRespError(xmlData) + "\n" + xmlData;
//            log.info("返回xml:" + xmlData);
            GetAgreementPriceResp getAgreementPriceResp = XMLUtil.convertXmlToObject(xmlData, GetAgreementPriceResp.class);
//            log.info("返回对象:"+JsonUtil.toString(getAgreementPriceResp));
            if (null == getAgreementPriceResp) {
                log.error("getAgreementPriceResp error respData {}", xmlData);
                throw new RuntimeException("获取房态信息为空");
            }
            if (!"SUCCESS".equals(getAgreementPriceResp.getResult())) {
                log.error("getAgreementPriceResp error respData {}", xmlData);
                throw new RuntimeException("查询失败");
            }
            return getAgreementPriceResp;
        } catch (Exception e) {
            throw new RuntimeException(errorStr + "\n" + e.getMessage());
        }
    }

    @Override
    public BookingCheckAgreementResp bookingCheckAgreement(BookingCheckAgreementReq bookingCheckAgreementReq) {
        if (StringUtils.isBlank(bookingCheckAgreementReq.getHotelCode())) {
            throw new RuntimeException("酒店编号为空");
        }
        if (StringUtils.isBlank(bookingCheckAgreementReq.getStartDate()) || StringUtils.isBlank(bookingCheckAgreementReq.getEndDate())) {
            throw new RuntimeException("开始或结束日期为空");
        }
        String errorStr = "";
        try {
//            log.info("请求对象:" + JsonUtil.toString(bookingCheckAgreementReq));
//            log.info("请求xml:" + XMLUtil.convertObjectToXml(bookingCheckAgreementReq));
            String xmlData = greenTreeOrderClient.bookingCheckAgreement(buildParam(XMLUtil.convertObjectToXml(bookingCheckAgreementReq)));
            errorStr = getRespError(xmlData) + "\n" + xmlData;
//            log.info("返回xml:" + xmlData);
            BookingCheckAgreementResp bookingCheckAgreementResp = XMLUtil.convertXmlToObject(xmlData, BookingCheckAgreementResp.class);
//            log.info("返回对象:"+JsonUtil.toString(bookingCheckAgreementResp));
            if (null == bookingCheckAgreementResp) {
                log.error("bookingCheckAgreementResp error respData {}", xmlData);
                throw new RuntimeException("下单检查信息为空");
            }
            if (!"SUCCESS".equals(bookingCheckAgreementResp.getResult())) {
                log.error("bookingCheckAgreementResp error respData {}", xmlData);
                throw new RuntimeException("下单检查失败");
            }
            return bookingCheckAgreementResp;
        } catch (Exception e) {
            throw new RuntimeException(errorStr + "\n" + e.getMessage());
        }
    }

    @Override
    public CreateBookingAgreementResp createBookingAgreement(CreateBookingAgreementReq createBookingAgreementReq) {
        String errorStr = "";
        try {
            // 下单
//            log.info("请求对象:" + JsonUtil.toString(createBookingAgreementReq));
//            log.info("请求xml:" + XMLUtil.convertObjectToXml(createBookingAgreementReq));
            String xmlData = greenTreeOrderClient.createBookingAgreement(buildParam(XMLUtil.convertObjectToXml(createBookingAgreementReq)));
            errorStr = getRespError(xmlData) + "\n" + xmlData;
//            log.info("返回xml:" + xmlData);
            CreateBookingAgreementResp createBookingAgreementResp = XMLUtil.convertXmlToObject(xmlData, CreateBookingAgreementResp.class);
//            log.info("返回对象:"+JsonUtil.toString(createBookingAgreementResp));
            if (null == createBookingAgreementResp) {
                log.error("createBookingAgreementResp error respData {}", xmlData);
                throw new RuntimeException("协议下单信息为空");
            }
            if (!"SUCCESS".equals(createBookingAgreementResp.getResult())) {
                log.error("createBookingAgreementResp error respData {}", xmlData);
                throw new RuntimeException("协议下单失败");
            }
            return createBookingAgreementResp;
        } catch (Exception e) {
            throw new RuntimeException(errorStr + "\n" + e.getMessage());
        }
    }

    @Override
    public OrderDataResult postAgreementOrder(CreateBookingAgreementReq createBookingAgreementReq, PriceCheckParam priceCheck, Integer breakfastCount, String bookId) {
        String errorStr = "";
        try {
            // 下单前校验
            BookingCheckAgreementReq bookingCheckAgreementReq = getCreateBookingAgreementReqInfo(createBookingAgreementReq);
            BookingCheckAgreementResp bookingCheckAgreementResp = bookingCheckAgreement(bookingCheckAgreementReq);

            // 容差判断
            BigDecimal raisedTotalPrice = BigDecimal.valueOf(0);
            // 房间多天总价格
            BigDecimal greentreeTotalRate = BigDecimal.ZERO;
            List<BookingCheckAgreementResp.ReqRooms.ReqDate.ReqRoom.AgreementRate> roomRateLists = bookingCheckAgreementResp.getReqRooms().getReqDate()
                    .stream().map(e -> e.getReqRoom().getAgreementRate()).collect(Collectors.toList());
            for (BookingCheckAgreementResp.ReqRooms.ReqDate.ReqRoom.AgreementRate roomRate : roomRateLists) {
                raisedTotalPrice = raisedTotalPrice.add(
                        priceCheck.getRaiseFunc().apply(roomRate.getPrice()));
                greentreeTotalRate = greentreeTotalRate.add(roomRate.getPrice());
            }
            // 取一天里的房间数量
            Integer roomCount = createBookingAgreementReq.getReservationInfo().getReqRooms().getReqRoom().getRoomCount();
            // todo 目前原价判断，无容差
            if (priceCheck.getTotalRate().compareTo(greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount))
                    .subtract(priceCheck.getTolerancePrice())) < 0) {
                String error = String.format("订单销售价不能低于采购总价，订单销售价=%s，采购总价=%s, 容差金额=%s, 目前差额=%s",
                        priceCheck.getTotalRate(),
                        greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount)),
                        priceCheck.getTolerancePrice(),
                        greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount)).subtract(priceCheck.getTotalRate()));
                hotelCommonTaskService.insertOrderErrorLog(createBookingAgreementReq.getReservationInfo().getAgentUniqueID(),
                        JsonUtil.toString(createBookingAgreementReq), error);
                log.error("订单销售价不能低于采购总价，订单销售价={}，采购总价={}, 容差金额={}, 目前差额={}",
                        priceCheck.getTotalRate(), greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount))
                        , priceCheck.getTolerancePrice(),
                        greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount)).subtract(priceCheck.getTotalRate()));
                throw new RuntimeException("订单销售价不能低于采购总价");
            }

            // todo 替换金额
//            CreateBookingAgreementReq.ReservationInfo reservationInfo = new CreateBookingAgreem
//            createBookingAgreementReq.getReservationInfo();
            createBookingAgreementReq.getReservationInfo().setComment(
                    String.format(
                            "|费用总计:%.2f|含早情况：%d,房费由嘉程商旅支付,杂费客人自理，渠道开具发票，嘉程商旅订单号:%s 嘉程商旅客服电话：%s（请报嘉程商旅订单号），价格保密",
                            greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount)),
                            breakfastCount,
                            bookId,
                            "0571-22934358")
            );
            // 添加首晚金额
            BookingCheckAgreementResp.ReqRooms.ReqDate reqDate = bookingCheckAgreementResp.getReqRooms().getReqDate().stream()
                    .filter(e -> e.getDate().equals(createBookingAgreementReq.getReservationInfo().getStartDate()))
                    .findFirst().orElse(null);
            createBookingAgreementReq.getReservationInfo().getReqRooms().getReqRoom()
                    .setAgreeRate(CreateBookingAgreementReq.AgreeRate.builder()
                            .currencyCode("CNY")
                            .price(reqDate.getReqRoom().getAgreementRate().getPrice())
                            .build());

            // 下单
            CreateBookingAgreementResp createBookingAgreementResp = createBookingAgreement(createBookingAgreementReq);
            return OrderDataResult.builder()
                    .orderCode(createBookingAgreementResp.getUniqueID()) //订单编号
                    .externalId(createBookingAgreementResp.getReservationInfo().getAgentUniqueID()) //中介订单号
                    .orderState(OrderStatusEnum.BOOK_SUCCESS.getCode())
                    .totalRate(greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount)))
                    .requestJsonStr(JsonUtil.toString(createBookingAgreementReq))
                    .responseJsonStr(JsonUtil.toString(createBookingAgreementResp))
                    .build();
        } catch (Exception e) {
            throw new RuntimeException(errorStr + "\n" + e.getMessage());
        }
    }

    @Override
    public OrderDataResult postActivityOrder(CreateBookingActivityReq createBookingActivityReq, PriceCheckParam priceCheck, Integer breakfastCount, String bookId) {
        try {
            // 下单前校验
            BookingCheckActivityReq bookingCheckActivityReq = getCreateBookingActivityReqInfo(createBookingActivityReq);
//            log.info("下单校验请求参数:" + JsonUtil.toString(bookingCheckActivityReq));
            BookingCheckActivityResp bookingCheckActivityResp = bookingCheckActivity(bookingCheckActivityReq);
//            log.info("下单校验返回参数:" + JsonUtil.toString(bookingCheckActivityResp));
            // 容差判断
            BigDecimal raisedTotalPrice = BigDecimal.valueOf(0);
            // 房间多天总价格
            BigDecimal greentreeTotalRate = BigDecimal.ZERO;
            List<BookingCheckActivityResp.ReqRooms.ReqDate.ReqRoom.RoomRate> roomRateLists = bookingCheckActivityResp.getReqRooms().getReqDate()
                    .stream().map(e -> e.getReqRoom().getRoomRate()).collect(Collectors.toList());
            for (BookingCheckActivityResp.ReqRooms.ReqDate.ReqRoom.RoomRate roomRate : roomRateLists) {
                raisedTotalPrice = raisedTotalPrice.add(
                        priceCheck.getRaiseFunc().apply(roomRate.getPrice()));
                greentreeTotalRate = greentreeTotalRate.add(roomRate.getPrice());
            }
            // 取一天里的房间数量
            Integer roomCount = createBookingActivityReq.getReservationInfo().getReqRooms().getReqRoom().getRoomCount();
            // todo 目前原价判断
            if (priceCheck.getTotalRate().compareTo(greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount))
                    .subtract(priceCheck.getTolerancePrice())) < 0) {
                String error = String.format("订单销售价不能低于采购总价，订单销售价=%s，采购总价=%s, 容差金额=%s, 目前差额=%s",
                        priceCheck.getTotalRate(),
                        greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount)),
                        priceCheck.getTolerancePrice(),
                        greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount)).subtract(priceCheck.getTotalRate()));
                hotelCommonTaskService.insertOrderErrorLog(createBookingActivityReq.getReservationInfo().getAgentUniqueID(),
                        JsonUtil.toString(createBookingActivityReq), error);
                log.error("订单销售价不能低于采购总价，订单销售价={}，采购总价={}, 容差金额={}, 目前差额={}",
                        priceCheck.getTotalRate(), greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount))
                        , priceCheck.getTolerancePrice(),
                        greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount)).subtract(priceCheck.getTotalRate()));
                throw new RuntimeException("订单销售价不能低于采购总价");
            }

            // todo 替换金额
            createBookingActivityReq.getReservationInfo().setComment(
                    String.format(
                            "|费用总计:%.2f|含早情况：%d,房费由嘉程商旅支付,杂费客人自理，渠道开具发票，嘉程商旅订单号:%s 嘉程商旅客服电话：%s（请报嘉程商旅订单号），价格保密",
                            greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount)),
                            breakfastCount,
                            bookId,
                            "0571-22934358")
            );
            // 添加首晚金额
            BookingCheckActivityResp.ReqRooms.ReqDate reqDate = bookingCheckActivityResp.getReqRooms().getReqDate().stream()
                    .filter(e -> e.getDate().equals(createBookingActivityReq.getReservationInfo().getStartDate()))
                    .findFirst().orElse(null);
            createBookingActivityReq.getReservationInfo().getReqRooms().getReqRoom()
                    .setRoomRate(CreateBookingActivityReq.ReservationInfo.ReqRooms.ReqRoom.RoomRate.builder()
                            .currencyCode("CNY")
                            .price(reqDate.getReqRoom().getRoomRate().getPrice())
                            .build());

            CreateBookingActivityResp createBookingActivityResp = createBookingActivity(createBookingActivityReq);
            return OrderDataResult.builder()
                    .orderCode(createBookingActivityResp.getUniqueID()) //订单编号
                    .externalId(createBookingActivityResp.getReservationInfo().getAgentUniqueID()) //中介订单号
                    .orderState(OrderStatusEnum.BOOK_SUCCESS.getCode())
                    .totalRate(greentreeTotalRate.multiply(BigDecimal.valueOf(roomCount)))
                    .requestJsonStr(JsonUtil.toString(createBookingActivityReq))
                    .responseJsonStr(JsonUtil.toString(createBookingActivityResp))
                    .build();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 拷贝活动下单对象值到活动校验对象
     */
    private BookingCheckActivityReq getCreateBookingActivityReqInfo(CreateBookingActivityReq createBookingActivityReq) {
        return BookingCheckActivityReq.builder()
                .hotelCode(createBookingActivityReq.getReservationInfo().getHotelCode())
                .startDate(createBookingActivityReq.getReservationInfo().getStartDate())
                .endDate(createBookingActivityReq.getReservationInfo().getEndDate())
                .reqRooms(BookingCheckActivityReq.ReqRooms.builder()
                        .reqRoom(BookingCheckActivityReq.ReqRooms.ReqRoom.builder()
                                .activityCode(createBookingActivityReq.getReservationInfo().getActivityCode())
                                .roomCount(createBookingActivityReq.getReservationInfo().getReqRooms().getReqRoom().getRoomCount())
                                .roomTypeCode(createBookingActivityReq.getReservationInfo().getReqRooms().getReqRoom().getRoomTypeCode())
                                .build())
                        .build())
                .build();
    }

    /**
     * 拷贝协议下单对象值到协议校验对象
     */
    private BookingCheckAgreementReq getCreateBookingAgreementReqInfo(CreateBookingAgreementReq createBookingAgreementReq) {
        BookingCheckAgreementReq bookingCheckAgreementReq = BookingCheckAgreementReq.builder()
                .startDate(createBookingAgreementReq.getReservationInfo().getStartDate()) // 开始日期
                .endDate(createBookingAgreementReq.getReservationInfo().getEndDate()) // 结束日期
                .hotelCode(createBookingAgreementReq.getReservationInfo().getHotelCode()) // 酒店编号
                .reqRooms(BookingCheckAgreementReq.ReqRooms.builder()
                        .reqRoom(BookingCheckAgreementReq.ReqRooms.ReqRoom.builder()
                                .roomTypeCode(createBookingAgreementReq.getReservationInfo().getReqRooms().getReqRoom().getRoomTypeCode()) // 房型编号
                                .roomCount(createBookingAgreementReq.getReservationInfo().getReqRooms().getReqRoom().getRoomCount()) // 请求房量
                                .build())
                        .build())
                .build();
        bookingCheckAgreementReq.setChainCode(createBookingAgreementReq.getChainCode());
        return bookingCheckAgreementReq;
    }

    private String getRespError(String myXml) {
        Pattern regx = Pattern.compile("<Msg>(.*?)</Msg>");
        Matcher matcher = regx.matcher(myXml);
        if (matcher.find()) {
            return matcher.group(1);
        }
        return "";
    }

    private String getCommitPrice(String info) {
        Pattern regx1 = Pattern.compile("|费用总计:(.*?)|");
        Pattern regx2 = Pattern.compile("|费用总计：(.*?)|");
        Matcher matcher1 = regx1.matcher(info);
        Matcher matcher2 = regx2.matcher(info);
        if (matcher1.find()) {
            return matcher1.group(1);
        }
        if (matcher2.find()) {
            return matcher2.group(1);
        }
        return "";
    }

    private MultiValueMap<String, String> buildParam(String req) {
        MultiValueMap<String, String> postData = new LinkedMultiValueMap<>();
        postData.add("requestXml", req);
        return postData;
    }

}
